package com.mju.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.mju.config.AlipayClientConfig;
import com.mju.controller.common.JsonResult;
import com.mju.feign.clients.*;
import com.mju.feign.pojo.VipReq;
import com.mju.pojo.Order;
import com.mju.pojo.Receive;
import com.mju.pojo.RefundInfo;
import com.mju.utils.VipNoUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Transactional(rollbackFor = Exception.class)
@Service
public class AliPayServiceImpl implements IAliPayService {
  @Autowired private AlipayClient alipayClient;
  @Autowired private OrderClient orderClient;
  @Autowired private PaymentInfoClient paymentInfoClient;
  @Autowired private RefundInfoClient refundInfoClient;
  @Autowired private VipClient vipClient;
  @Autowired
  private ReceiveClient receiveClient;

  @SneakyThrows
  public String createPay(Order order, String uid) {

    // 设置请求参数
    AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
    alipayRequest.setReturnUrl(AlipayClientConfig.returnUrl);
    alipayRequest.setNotifyUrl(AlipayClientConfig.notifyUrl);

    // 商户订单号，商户网站订单系统中唯一订单号，必填
    String out_trade_no = String.valueOf(order.getOid());
    // 付款金额，必填
    String total_amount = String.valueOf(order.getTotalPrice());
    // 订单名称，必填
    String subject = "待支付订单";

    // 该笔订单允许的最晚付款时间，逾期将关闭交易。取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。
    // 该参数数值不接受小数点， 如 1.5h，可转换为 90m。
    String timeout_express = "30m";

    String passback_params = String.valueOf(uid);
    // 对取得的数据进行URLEncoder编码，这一步不做会报错
    String uidStr = URLEncoder.encode(passback_params, "UTF-8");

    // 将编码后的数据封装在alipayRequest对象中，参数名字一定要是passback_params才能在异步通知时返回
    // 至于参数的变量值这没有要求，只需要与上方编码后的一样即可
    AlipayTradePagePayModel model = new AlipayTradePagePayModel();
    model.setOutTradeNo(out_trade_no);
    model.setSubject(subject);
    model.setTotalAmount(total_amount);
    model.setPassbackParams(uidStr);
    model.setTimeoutExpress(timeout_express);
    model.setProductCode("FAST_INSTANT_TRADE_PAY");
    //    model.setProductCode("PRE_AUTH");
    //    model.setProductCode("PRE_AUTH_ONLINE");

    alipayRequest.setBizModel(model);

    // 请求支付宝后台获取的数据，会返回一个表单
    AlipayTradePagePayResponse response = null;
    try {
      // 完成签名并执行请求
      response = alipayClient.pageExecute(alipayRequest);
      if (response.isSuccess()) {
        log.info("创建交易支付成功...");
        return response.getBody();
      } else {
        log.error("创建交易支付失败...");
        log.error(response.getMsg());
        return null;
      }
    } catch (AlipayApiException e) {
      log.error("创建交易支付异常...");
      return null;
    }
  }

  @SneakyThrows
  public String createPayForMobileTerminal(Order order, String uid) {

    // 设置请求参数
    AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
    alipayRequest.setReturnUrl(AlipayClientConfig.returnUrlForMobileTerminal);
    alipayRequest.setNotifyUrl(AlipayClientConfig.notifyUrlForMobileTerminal);

    // 商户订单号，商户网站订单系统中唯一订单号，必填
    String out_trade_no = String.valueOf(order.getOid());
    // 付款金额，必填
    String total_amount = String.valueOf(order.getTotalPrice());
    // 订单名称，必填
    String subject = "待支付订单";

    // 该笔订单允许的最晚付款时间，逾期将关闭交易。取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。
    // 该参数数值不接受小数点， 如 1.5h，可转换为 90m。
    String timeout_express = "30m";

    String passback_params = String.valueOf(uid);
    // 对取得的数据进行URLEncoder编码，这一步不做会报错
    String uidStr = URLEncoder.encode(passback_params, "UTF-8");

    // 将编码后的数据封装在alipayRequest对象中，参数名字一定要是passback_params才能在异步通知时返回
    // 至于参数的变量值这没有要求，只需要与上方编码后的一样即可
    AlipayTradePagePayModel model = new AlipayTradePagePayModel();
    model.setOutTradeNo(out_trade_no);
    model.setSubject(subject);
    model.setTotalAmount(total_amount);
    model.setPassbackParams(uidStr);
    model.setTimeoutExpress(timeout_express);
    model.setProductCode("FAST_INSTANT_TRADE_PAY");
    //    model.setProductCode("PRE_AUTH");
    //    model.setProductCode("PRE_AUTH_ONLINE");

    alipayRequest.setBizModel(model);

    // 请求支付宝后台获取的数据，会返回一个表单
    AlipayTradePagePayResponse response = null;
    try {
      // 完成签名并执行请求
      response = alipayClient.pageExecute(alipayRequest);
      if (response.isSuccess()) {
        log.info("创建交易支付成功...");
        return response.getBody();
      } else {
        log.error("创建交易支付失败...");
        log.error(response.getMsg());
        return null;
      }
    } catch (AlipayApiException e) {
      log.error("创建交易支付异常...");
      return null;
    }
  }

  @SneakyThrows
  public String buyVip(String vipName, String uid, Integer day, Integer amount) {

    // 设置请求参数
    AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
    alipayRequest.setReturnUrl(AlipayClientConfig.returnUrlForVip);
    alipayRequest.setNotifyUrl(AlipayClientConfig.notifyUrlForVip);

    // 购买VIP订单号，商户网站订单系统中唯一订单号，必填
    String out_trade_no = VipNoUtils.getVIPNo();
    // 付款金额，必填
    String total_amount = String.valueOf(amount);
    // 订单名称，必填
    String subject = "购买" + vipName;

    // 该笔订单允许的最晚付款时间，逾期将关闭交易。取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。
    // 该参数数值不接受小数点， 如 1.5h，可转换为 90m。
    String timeout_express = "30m";

    Map<String, String> map = new HashMap<>();
    map.put("vipName", vipName);
    map.put("uid", uid);
    map.put("day", String.valueOf(day));
    String passback_params = JSON.toJSONString(map);
    // 对取得的数据进行URLEncoder编码，这一步不做会报错
    String paramsStr = URLEncoder.encode(passback_params, "UTF-8");

    // 将编码后的数据封装在alipayRequest对象中，参数名字一定要是passback_params才能在异步通知时返回
    // 至于参数的变量值这没有要求，只需要与上方编码后的一样即可
    AlipayTradePagePayModel model = new AlipayTradePagePayModel();
    model.setOutTradeNo(out_trade_no);
    model.setSubject(subject);
    model.setTotalAmount(total_amount);
    model.setPassbackParams(paramsStr);
    model.setTimeoutExpress(timeout_express);
    model.setProductCode("FAST_INSTANT_TRADE_PAY");
    //    model.setProductCode("PRE_AUTH");
    //    model.setProductCode("PRE_AUTH_ONLINE");

    alipayRequest.setBizModel(model);

    // 请求支付宝后台获取的数据，会返回一个表单
    AlipayTradePagePayResponse response = null;
    try {
      // 完成签名并执行请求
      response = alipayClient.pageExecute(alipayRequest);
      if (response.isSuccess()) {
        log.info("购买VIP支付成功...");
        return response.getBody();
      } else {
        log.error("购买VIP支付失败...");
        log.error(response.getMsg());
        return null;
      }
    } catch (AlipayApiException e) {
      log.error("购买VIP支付异常...");
      return null;
    }
  }

  /**
   * 处理VIP交易
   *
   * @param params
   */
  @SneakyThrows
  @Override
  public void processVip(Map<String, String> params) {
    log.info("处理VIP订单...");

    // 获取用户uid
    // 获取在支付接口中保存的uid
    String passback_params = params.get("passback_params");
    // 对传回的数据进行编码的逆过程，对参数进行解码
    String paramsStr = URLDecoder.decode(passback_params, "UTF-8");
    Map<String, String> map = JSON.parseObject(paramsStr, new TypeReference<HashMap<String, String>>() {});
    String vipName = map.get("vipName");
    Integer uid = Integer.parseInt(map.get("uid"));
    Integer day = Integer.parseInt(map.get("day"));
    log.info("接收到的uid==>"+uid+"，接收到的day==>"+day);
    // 更新用户VIP状态 1-是VIP用户
    VipReq vipReq = new VipReq();
    vipReq.setVipName(vipName);
    vipReq.setUid(uid);
    vipReq.setDay(day);
    vipClient.activateVip(vipReq);

    // 记录支付信息
    //    paymentInfoService.createPaymentInfo(params);
    paymentInfoClient.createPaymentInfo(params);
  }

  @Override
  public void processOrder(Map<String, String> params) {
    log.info("处理订单...");

    // 获取订单号
    Integer oid = Integer.parseInt(params.get("out_trade_no"));

    // 更新订单状态 1-已支付
    //    orderService.updateStatusByOid(oid, 1);
    orderClient.updateOrderStatus(oid, 1);

    // 记录支付信息
    //    paymentInfoService.createPaymentInfo(params);
    paymentInfoClient.createPaymentInfo(params);
  }

  @Override
  public void processOrderForMobileTerminal(Map<String, String> params) {
    log.info("处理订单...");

    // 获取订单号
    Integer oid = Integer.parseInt(params.get("out_trade_no"));

    // 更新订单状态 1-已支付
    //    orderService.updateStatusByOid(oid, 1);
    orderClient.updateOrderStatus(oid, 1);

    // 记录移动端支付信息
    //    paymentInfoService.createPaymentInfo(params);
    paymentInfoClient.createPaymentInfoForMobileTerminal(params);
  }

  @Override
  public void cancelOrder(Integer oid) {
    // 调用支付宝提供的统一收单交易关闭接口
    this.closeOrder(oid);

    // 更细用户订单状态 2-已取消
    //    orderService.updateStatusByOid(oid, 2);
    orderClient.updateOrderStatus(oid, 2);
  }

  @Override
  public void closeOrder(Integer oid) {
    try {
      log.info("关闭订单接口的调用，订单号为：" + oid);

      AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
      String outTradeNo = String.valueOf(oid);

      // 数据
      AlipayTradeRefundModel bizModel = new AlipayTradeRefundModel();
      // 订单号
      bizModel.setOutTradeNo(outTradeNo);
      request.setBizModel(bizModel);

      AlipayTradeCloseResponse response = alipayClient.execute(request);
      if (response.isSuccess()) {
        log.info("关闭订单接口调用成功...");
        log.info("通知参数为" + response.getBody());
      } else {
        log.error("关闭订单接口调用失败...");
      }
    } catch (AlipayApiException e) {
      log.error("关闭订单接口调用异常...");
    }
  }

  @Override
  public void refundOrder(Integer oid, String reason) {
    try {
      log.info("订单退款接口的调用，订单号为：" + oid);

      JsonResult<RefundInfo> data = refundInfoClient.createrRefundByOrder(oid, reason);
      RefundInfo refundInfo = data.getData();
      //      RefundInfo refundInfo = refundInfoService.createrRefundByOrder(oid, reason);

      AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();

      // 数据
      AlipayTradeRefundModel bizModel = new AlipayTradeRefundModel();
      // 订单号
      bizModel.setOutTradeNo(refundInfo.getOrderNo());
      // 退款单号
      bizModel.setOutRequestNo(refundInfo.getRefundId());
      // 退款金额，不能大于支付金额
      String refund = String.valueOf(new BigDecimal(refundInfo.getRefund().toString()));
      bizModel.setRefundAmount(refund);
      // 退款原因
      bizModel.setRefundReason(refundInfo.getReason());
      request.setBizModel(bizModel);

      //      // 返回参数选项，按需传入
      //      JSONObject bizContent = new JSONObject();
      //      JSONArray queryOptions = new JSONArray();
      //      queryOptions.add("refund_detail_item_list");
      //      bizContent.put("query_options", queryOptions);
      //      request.setBizContent(bizContent.toString());

      AlipayTradeRefundResponse response = alipayClient.execute(request);
      if (response.isSuccess()) {
        log.info("订单退款接口调用成功...");
        log.info("返回参数" + response.getBody());

        // 更新订单状态
        //        orderService.updateStatusByOid(oid, 5);
        orderClient.updateOrderStatus(oid, 5);

        String refundStatus = "REFUND_SUCCESS";
        // 更新退款信息
        refundInfoClient.updateRefund(
            refundInfo.getRefundNo(), response.getTradeNo(), response.getBody(), refundStatus);
        //        refundInfoService.updateRefund(refundInfo.getRefundNo(),response.getTradeNo(),
        // response.getBody(), refundStatus);
      } else {
        log.error("订单退款接口调用失败...");
        // 更新订单状态
        //        orderService.updateStatusByOid(oid, 6);
        orderClient.updateOrderStatus(oid, 6);

        String refundStatus = "REFUND_ABNORMAL";
        // 更新退款信息
        refundInfoClient.updateRefund(
            refundInfo.getRefundNo(), response.getTradeNo(), response.getBody(), refundStatus);
        //        refundInfoService.updateRefund(refundInfo.getRefundNo(),response.getTradeNo(),
        // response.getBody(), refundStatus);
      }
    } catch (AlipayApiException e) {
      log.error("订单退款接口调用异常...");
    }
  }

  @Override
  public String queryBill(String billDate, String billType) {
    try {
      log.info("调用支付宝对账接口...");
      // 请求
      AlipayDataDataserviceBillDownloadurlQueryRequest request =
          new AlipayDataDataserviceBillDownloadurlQueryRequest();
      // 数据
      AlipayDataDataserviceBillDownloadurlQueryModel bizModel =
          new AlipayDataDataserviceBillDownloadurlQueryModel();
      bizModel.setBillDate(billDate);
      bizModel.setBillType(billType);
      request.setBizModel(bizModel);

      // 完成签名并执行请求
      AlipayDataDataserviceBillDownloadurlQueryResponse response = alipayClient.execute(request);
      if (response.isSuccess()) {
        log.info("获取账单下载url成功...");
        log.info("通知参数为" + response.getBody());
        return response.getBillDownloadUrl();
      } else {
        log.error("获取账单下载url失败...");
        return null;
      }
    } catch (AlipayApiException e) {
      log.error("获取账单下载url异常...");
      return null;
    }
  }

  @SneakyThrows
  @Override
  public String transferAccounts(String accountNumber, String payeeName, Receive receive) {
    log.info("开始打款------账号：" + accountNumber + "收款人姓名：" + payeeName);
    AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
    AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();

    // 单号
    model.setOutBizNo(String.valueOf(receive.getRId()));
    // 转账金额
    model.setTransAmount(String.valueOf(receive.getFinalPrice()));
    // 转账到支付宝
    model.setBizScene("DIRECT_TRANSFER");
    model.setProductCode("TRANS_ACCOUNT_NO_PWD");
    // 标题
    model.setOrderTitle("二手物品打款");

    // 商户信息
    Participant payerInfo = new Participant();
    payerInfo.setIdentity("2088721003893546");
    payerInfo.setIdentityType("ALIPAY_USER_ID");
    model.setPayerInfo(payerInfo);

    // 收款人信息
    Participant payeeInfo = new Participant();
    payeeInfo.setIdentity("lcvake9353@sandbox.com");
    payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
    payeeInfo.setName("lcvake9353");

    // 打款信息
    BankcardExtInfo bankcardExtInfo = new BankcardExtInfo();
    bankcardExtInfo.setInstName("Mint购物商城");
    bankcardExtInfo.setAccountType("1");

    payeeInfo.setBankcardExtInfo(bankcardExtInfo);
    model.setPayeeInfo(payeeInfo);
    request.setBizModel(model);
    AlipayFundTransUniTransferResponse response = alipayClient.execute(request);
    //RSA2密钥请求response = alipayClient.execute(request);
    // 公钥证书请求请求 response = alipayClient.certificateExecute(request);
    System.out.println(response.getBody());

    if (receiveClient.getStatusByRid(receive.getRId()) == 4) {
      return "请勿重复打款...";
    }

    if (response.isSuccess()) {
      // 双层校验
      if (this.checkTransfer(response.getOrderId())) {
        receiveClient.completeReceive(receive.getRId());
        return "打款成功";
      }
      return "打款失败";
    } else {
      return response.getSubMsg();
    }
  }

  @SneakyThrows
  @Override
  public boolean checkTransfer(String orderId) {
    log.info("校验是否打款成功...");
    AlipayFundTransCommonQueryRequest request = new AlipayFundTransCommonQueryRequest();
    AlipayFundTransCommonQueryModel model = new AlipayFundTransCommonQueryModel();
    // 产品码 单笔无密转账到银行卡
    model.setProductCode("TRANS_ACCOUNT_NO_PWD");
    // 业务场景 单笔无密转账
    model.setBizScene("DIRECT_TRANSFER");
    // 订单流水号
    model.setOrderId(orderId);
    request.setBizModel(model);
    AlipayFundTransCommonQueryResponse response = alipayClient.execute(request);
    System.out.println(response.getBody());
    return response.isSuccess();
  }
}
